home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 2005 March / Macworld CD March 2005 - Marathon Trilogy.iso / Shareware World / iPod / iPodderX.sit / iPodderX / iPodderX.app / Contents / Resources / Connecter.pyc (.txt) < prev    next >
Encoding:
Python Compiled Bytecode  |  2005-01-07  |  20.0 KB  |  445 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyc (Python 2.3)
  3.  
  4. from bitfield import Bitfield
  5. from binascii import b2a_hex
  6. from CurrentRateMeasure import Measure
  7.  
  8. def toint(s):
  9.     return long(b2a_hex(s), 16)
  10.  
  11.  
  12. def tobinary(i):
  13.     return chr(i >> 24) + chr(i >> 16 & 255) + chr(i >> 8 & 255) + chr(i & 255)
  14.  
  15. CHOKE = chr(0)
  16. UNCHOKE = chr(1)
  17. INTERESTED = chr(2)
  18. NOT_INTERESTED = chr(3)
  19. HAVE = chr(4)
  20. BITFIELD = chr(5)
  21. REQUEST = chr(6)
  22. PIECE = chr(7)
  23. CANCEL = chr(8)
  24.  
  25. class Connection:
  26.     
  27.     def __init__(self, connection, connecter):
  28.         self.connection = connection
  29.         self.connecter = connecter
  30.         self.got_anything = False
  31.  
  32.     
  33.     def get_ip(self):
  34.         return self.connection.get_ip()
  35.  
  36.     
  37.     def get_id(self):
  38.         return self.connection.get_id()
  39.  
  40.     
  41.     def close(self):
  42.         self.connection.close()
  43.  
  44.     
  45.     def is_flushed(self):
  46.         if self.connecter.rate_capped:
  47.             return False
  48.         
  49.         return self.connection.is_flushed()
  50.  
  51.     
  52.     def is_locally_initiated(self):
  53.         return self.connection.is_locally_initiated()
  54.  
  55.     
  56.     def send_interested(self):
  57.         self.connection.send_message(INTERESTED)
  58.  
  59.     
  60.     def send_not_interested(self):
  61.         self.connection.send_message(NOT_INTERESTED)
  62.  
  63.     
  64.     def send_choke(self):
  65.         self.connection.send_message(CHOKE)
  66.  
  67.     
  68.     def send_unchoke(self):
  69.         self.connection.send_message(UNCHOKE)
  70.  
  71.     
  72.     def send_request(self, index, begin, length):
  73.         self.connection.send_message(REQUEST + tobinary(index) + tobinary(begin) + tobinary(length))
  74.  
  75.     
  76.     def send_cancel(self, index, begin, length):
  77.         self.connection.send_message(CANCEL + tobinary(index) + tobinary(begin) + tobinary(length))
  78.  
  79.     
  80.     def send_piece(self, index, begin, piece):
  81.         if not not (self.connecter.rate_capped):
  82.             raise AssertionError
  83.         self.connecter._update_upload_rate(len(piece))
  84.         self.connection.send_message(PIECE + tobinary(index) + tobinary(begin) + piece)
  85.  
  86.     
  87.     def send_bitfield(self, bitfield):
  88.         self.connection.send_message(BITFIELD + bitfield)
  89.  
  90.     
  91.     def send_have(self, index):
  92.         self.connection.send_message(HAVE + tobinary(index))
  93.  
  94.     
  95.     def get_upload(self):
  96.         return self.upload
  97.  
  98.     
  99.     def get_download(self):
  100.         return self.download
  101.  
  102.  
  103.  
  104. class Connecter:
  105.     
  106.     def __init__(self, make_upload, downloader, choker, numpieces, totalup, max_upload_rate = 0, sched = None):
  107.         self.downloader = downloader
  108.         self.make_upload = make_upload
  109.         self.choker = choker
  110.         self.numpieces = numpieces
  111.         self.max_upload_rate = max_upload_rate
  112.         self.sched = sched
  113.         self.totalup = totalup
  114.         self.rate_capped = False
  115.         self.connections = { }
  116.  
  117.     
  118.     def _update_upload_rate(self, amount):
  119.         self.totalup.update_rate(amount)
  120.         if self.max_upload_rate > 0 and self.totalup.get_rate_noupdate() > self.max_upload_rate:
  121.             self.rate_capped = True
  122.             self.sched(self._uncap, self.totalup.time_until_rate(self.max_upload_rate))
  123.         
  124.  
  125.     
  126.     def _uncap(self):
  127.         self.rate_capped = False
  128.         while not (self.rate_capped):
  129.             up = None
  130.             minrate = None
  131.             for i in self.connections.values():
  132.                 if not i.upload.is_choked() and i.upload.has_queries() and i.connection.is_flushed():
  133.                     rate = i.upload.get_rate()
  134.                     if up is None or rate < minrate:
  135.                         up = i.upload
  136.                         minrate = rate
  137.                     
  138.                 rate < minrate
  139.             
  140.             if up is None:
  141.                 break
  142.             
  143.             up.flushed()
  144.             if self.totalup.get_rate_noupdate() > self.max_upload_rate:
  145.                 break
  146.                 continue
  147.  
  148.     
  149.     def change_max_upload_rate(self, newval):
  150.         
  151.         def foo(self = self, newval = newval):
  152.             self._change_max_upload_rate(newval)
  153.  
  154.         self.sched(foo, 0)
  155.  
  156.     
  157.     def _change_max_upload_rate(self, newval):
  158.         self.max_upload_rate = newval
  159.         self._uncap()
  160.  
  161.     
  162.     def how_many_connections(self):
  163.         return len(self.connections)
  164.  
  165.     
  166.     def connection_made(self, connection):
  167.         c = Connection(connection, self)
  168.         self.connections[connection] = c
  169.         c.upload = self.make_upload(c)
  170.         c.download = self.downloader.make_download(c)
  171.         self.choker.connection_made(c)
  172.  
  173.     
  174.     def connection_lost(self, connection):
  175.         c = self.connections[connection]
  176.         d = c.download
  177.         del self.connections[connection]
  178.         d.disconnected()
  179.         self.choker.connection_lost(c)
  180.  
  181.     
  182.     def connection_flushed(self, connection):
  183.         self.connections[connection].upload.flushed()
  184.  
  185.     
  186.     def got_message(self, connection, message):
  187.         c = self.connections[connection]
  188.         t = message[0]
  189.         if t == BITFIELD and c.got_anything:
  190.             connection.close()
  191.             return None
  192.         
  193.         c.got_anything = True
  194.         if t in [
  195.             CHOKE,
  196.             UNCHOKE,
  197.             INTERESTED,
  198.             NOT_INTERESTED] and len(message) != 1:
  199.             connection.close()
  200.             return None
  201.         
  202.         if t == CHOKE:
  203.             c.download.got_choke()
  204.         elif t == UNCHOKE:
  205.             c.download.got_unchoke()
  206.         elif t == INTERESTED:
  207.             c.upload.got_interested()
  208.         elif t == NOT_INTERESTED:
  209.             c.upload.got_not_interested()
  210.         elif t == HAVE:
  211.             if len(message) != 5:
  212.                 connection.close()
  213.                 return None
  214.             
  215.             i = toint(message[1:])
  216.             if i >= self.numpieces:
  217.                 connection.close()
  218.                 return None
  219.             
  220.             c.download.got_have(i)
  221.         elif t == BITFIELD:
  222.             
  223.             try:
  224.                 b = Bitfield(self.numpieces, message[1:])
  225.             except ValueError:
  226.                 connection.close()
  227.                 return None
  228.  
  229.             c.download.got_have_bitfield(b)
  230.         elif t == REQUEST:
  231.             if len(message) != 13:
  232.                 connection.close()
  233.                 return None
  234.             
  235.             i = toint(message[1:5])
  236.             if i >= self.numpieces:
  237.                 connection.close()
  238.                 return None
  239.             
  240.             c.upload.got_request(i, toint(message[5:9]), toint(message[9:]))
  241.         elif t == CANCEL:
  242.             if len(message) != 13:
  243.                 connection.close()
  244.                 return None
  245.             
  246.             i = toint(message[1:5])
  247.             if i >= self.numpieces:
  248.                 connection.close()
  249.                 return None
  250.             
  251.             c.upload.got_cancel(i, toint(message[5:9]), toint(message[9:]))
  252.         elif t == PIECE:
  253.             if len(message) <= 9:
  254.                 connection.close()
  255.                 return None
  256.             
  257.             i = toint(message[1:5])
  258.             if i >= self.numpieces:
  259.                 connection.close()
  260.                 return None
  261.             
  262.             if c.download.got_piece(i, toint(message[5:9]), message[9:]):
  263.                 for co in self.connections.values():
  264.                     co.send_have(i)
  265.                 
  266.             
  267.         else:
  268.             connection.close()
  269.  
  270.  
  271.  
  272. class DummyUpload:
  273.     
  274.     def __init__(self, events):
  275.         self.events = events
  276.         events.append('made upload')
  277.  
  278.     
  279.     def flushed(self):
  280.         self.events.append('flushed')
  281.  
  282.     
  283.     def got_interested(self):
  284.         self.events.append('interested')
  285.  
  286.     
  287.     def got_not_interested(self):
  288.         self.events.append('not interested')
  289.  
  290.     
  291.     def got_request(self, index, begin, length):
  292.         self.events.append(('request', index, begin, length))
  293.  
  294.     
  295.     def got_cancel(self, index, begin, length):
  296.         self.events.append(('cancel', index, begin, length))
  297.  
  298.  
  299.  
  300. class DummyDownload:
  301.     
  302.     def __init__(self, events):
  303.         self.events = events
  304.         events.append('made download')
  305.         self.hit = 0
  306.  
  307.     
  308.     def disconnected(self):
  309.         self.events.append('disconnected')
  310.  
  311.     
  312.     def got_choke(self):
  313.         self.events.append('choke')
  314.  
  315.     
  316.     def got_unchoke(self):
  317.         self.events.append('unchoke')
  318.  
  319.     
  320.     def got_have(self, i):
  321.         self.events.append(('have', i))
  322.  
  323.     
  324.     def got_have_bitfield(self, bitfield):
  325.         self.events.append(('bitfield', bitfield.tostring()))
  326.  
  327.     
  328.     def got_piece(self, index, begin, piece):
  329.         self.events.append(('piece', index, begin, piece))
  330.         self.hit += 1
  331.         return self.hit > 1
  332.  
  333.  
  334.  
  335. class DummyDownloader:
  336.     
  337.     def __init__(self, events):
  338.         self.events = events
  339.  
  340.     
  341.     def make_download(self, connection):
  342.         return DummyDownload(self.events)
  343.  
  344.  
  345.  
  346. class DummyConnection:
  347.     
  348.     def __init__(self, events):
  349.         self.events = events
  350.  
  351.     
  352.     def send_message(self, message):
  353.         self.events.append(('m', message))
  354.  
  355.  
  356.  
  357. class DummyChoker:
  358.     
  359.     def __init__(self, events, cs):
  360.         self.events = events
  361.         self.cs = cs
  362.  
  363.     
  364.     def connection_made(self, c):
  365.         self.events.append('made')
  366.         self.cs.append(c)
  367.  
  368.     
  369.     def connection_lost(self, c):
  370.         self.events.append('lost')
  371.  
  372.  
  373.  
  374. def test_operation():
  375.     events = []
  376.     cs = []
  377.     co = Connecter((lambda c, events = events: DummyUpload(events)), DummyDownloader(events), DummyChoker(events, cs), 3, Measure(10))
  378.     if not events == []:
  379.         raise AssertionError
  380.     if not cs == []:
  381.         raise AssertionError
  382.     dc = DummyConnection(events)
  383.     co.connection_made(dc)
  384.     if not len(cs) == 1:
  385.         raise AssertionError
  386.     cc = cs[0]
  387.     co.got_message(dc, BITFIELD + chr(192))
  388.     co.got_message(dc, CHOKE)
  389.     co.got_message(dc, UNCHOKE)
  390.     co.got_message(dc, INTERESTED)
  391.     co.got_message(dc, NOT_INTERESTED)
  392.     co.got_message(dc, HAVE + tobinary(2))
  393.     co.got_message(dc, REQUEST + tobinary(1) + tobinary(5) + tobinary(6))
  394.     co.got_message(dc, CANCEL + tobinary(2) + tobinary(3) + tobinary(4))
  395.     co.got_message(dc, PIECE + tobinary(1) + tobinary(0) + 'abc')
  396.     co.got_message(dc, PIECE + tobinary(1) + tobinary(3) + 'def')
  397.     co.connection_flushed(dc)
  398.     cc.send_bitfield(chr(96))
  399.     cc.send_interested()
  400.     cc.send_not_interested()
  401.     cc.send_choke()
  402.     cc.send_unchoke()
  403.     cc.send_have(4)
  404.     cc.send_request(0, 2, 1)
  405.     cc.send_cancel(1, 2, 3)
  406.     cc.send_piece(1, 2, 'abc')
  407.     co.connection_lost(dc)
  408.     x = [
  409.         'made upload',
  410.         'made download',
  411.         'made',
  412.         ('bitfield', chr(192)),
  413.         'choke',
  414.         'unchoke',
  415.         'interested',
  416.         'not interested',
  417.         ('have', 2),
  418.         ('request', 1, 5, 6),
  419.         ('cancel', 2, 3, 4),
  420.         ('piece', 1, 0, 'abc'),
  421.         ('piece', 1, 3, 'def'),
  422.         ('m', HAVE + tobinary(1)),
  423.         'flushed',
  424.         ('m', BITFIELD + chr(96)),
  425.         ('m', INTERESTED),
  426.         ('m', NOT_INTERESTED),
  427.         ('m', CHOKE),
  428.         ('m', UNCHOKE),
  429.         ('m', HAVE + tobinary(4)),
  430.         ('m', REQUEST + tobinary(0) + tobinary(2) + tobinary(1)),
  431.         ('m', CANCEL + tobinary(1) + tobinary(2) + tobinary(3)),
  432.         ('m', PIECE + tobinary(1) + tobinary(2) + 'abc'),
  433.         'disconnected',
  434.         'lost']
  435.     for a, b in zip(events, x):
  436.         if not a == b:
  437.             raise AssertionError, repr((a, b))
  438.     
  439.  
  440.  
  441. def test_conversion():
  442.     if not toint(tobinary(50000)) == 50000:
  443.         raise AssertionError
  444.  
  445.